import React, { useEffect, useRef, useState, useMemo, useCallback } from 'react';
import { Form, message, Spin } from 'antd';
import moment from 'moment';
import { connect } from 'umi';
import { debounce } from 'lodash';
import { PageContainer, WebAudio } from '@/molecules';
import pageTabUtil from '@/utils/pageTabUtil';
import { useRequest, defaultFormatResult } from '@/hooks';
import { Evaluation } from '@/pages/Recruitment/components';
import events from '@/utils/eventBus';
import useSharedSocket from '@/pages/Recruitment/Interview/hooks/useSharedSocket';
import useSocket from './hooks/useSocket';
import useMultiInterviewersV2 from './hooks/useMultiInterviewersV2';
import { TitleControl } from '../components';
import WEBSOCKET_TYPES from './utils/WEBSOCKET_TYPES';
import EVENTBUS_TYPES from './utils/EVENTBUS_TYPES';
import WARNING_TYPES from './utils/WARNING_TYPES';
import {
    showMessageHandler,
    passiveTriggerOnlineEvent,
    startFightForHost,
    handleFightEvent,
    handleResponseForFight
} from './utils/recWSEventHandlers';
import isCurrentPageActived from './utils/isCurrentPageActived';
import styles from './Record.less';
import AssessFrom from '../containers/AssessFrom';
import TalentInfoHead from '../components/TalentInfoHead';
import HoverRECButton from './Containers/HoverRECButton';
import AlarmAudioPlayer from './Containers/AlarmAudioPlayer';
import { RecordQuestion as Question } from './Containers';
import {
    getTalentMessage,
    getInterviewProcedure,
    onSaveInterviewprocedure,
    resetInterviewRecordState,
    getOtherQuestions,
    saveInterviewRecord
} from '../service';

import { useBeforeInterview } from './hooks';
import useRealTimeUpload from './hooks/useRealTimeUpload';

const currentUserCode = JSON.parse(localStorage.getItem('user') ?? null)?.employeeCode;
const isCurrentUser = code => code === currentUserCode;

const formatComment = source => (source || []).find(commentItem => isCurrentUser(commentItem.createUser)) || {};

let setRemoteRECDurationTimmer; // 非主录音者，控制录音时间 +1秒的计时器
let checkStartTimeTimmer; // 检查是否已超过面试开始时间的定时器
let hoverLoadingTimmer; // 悬浮录音条的loading状态定时器

/**
 * 检查当前用户是否有参与本场面试
 */
const checkIsPermitted = (list, user) => {
    if (list?.length) {
        for (let index = 0; index < list.length; index += 1) {
            const element = list[index];
            if (element.employeeCode === user) {
                return; // 用户参与面试，则不做操作
            }
        }
    }
    // 参考src/app.js 中 handleNoAuth
    sessionStorage.setItem('errorMsg', '系统冲突！检测到无对应权限，请确认权限配置！');
    pageTabUtil.goBack(); // 未参与面试，则关闭tab。
};

const Record = ({ user, form, location, dispatch }) => {
    const { arrangeId = 89, candidateId = 539 } = location.query;
    const { getFieldDecorator, validateFieldsAndScroll, getFieldValue, setFieldsValue } = form;
    const [interviewersArr, setInterviewersArr] = useState([]); // 面试官信息数组，userCode，姓名，头像
    const interviewersArrRef = useRef([]); // 面试官信息数组Ref，仅有userCode
    const [recruitEvaluateList, setRecruitEvaluateList] = useState([]);
    const [pageLoading, setPageLoading] = useState(true);
    const [remoteRECState, setRemoteRECState] = useState(-1); // 主录音者的录音状态，0停止， 1录制中， 2暂停
    const currentHref = useRef(window.location.href);
    const remoteRECStateRef = useRef(-1);
    const localBackupRef = useRef(JSON.parse(localStorage.getItem('recHOSTuserCode') || 'null'));
    const [recHOSTuserCode, setRecHOSTuserCode] = useState(
        localBackupRef.current && localBackupRef.current.arrangeId === arrangeId && localBackupRef.current.user === user
            ? user // 应对主录音是自己，且仅有一人在线时，刷新页面后的状态保存
            : ''
    ); // 主录音者的userCode
    const recHOSTuserCodeRef = useRef(''); // 主录音者的userCode Ref
    const wsuserCode = useRef(''); // 上线、离线者的userCode Ref
    const [remoteRECDuration, setRemoteRECDuration] = useState(0); // 远程录音者的录音时间
    const remoteRECDurationRef = useRef(0);
    const interviewStartTimeRef = useRef(999999999999999999); // 面试开始时间 timestamp
    const [warningType, setWarningType] = useState(WARNING_TYPES.NONE); // 录音悬浮窗，警示条
    const onlineOfflineTimmerRef = useRef(null); // 上下线提示定时器
    const warningRef = useRef(WARNING_TYPES.NONE);
    const proxySetWarningType = type => {
        setWarningType(type);
        warningRef.current = type;
    };
    const setWarningHandler = type => {
        if (onlineOfflineTimmerRef.current) {
            clearTimeout(onlineOfflineTimmerRef.current); // 当上下线提示信息还在显示中，此时有警告信息出来则清除上下线提示定时器
        }
        proxySetWarningType(type);
    };
    /**
     * 处理监听用户上下线状态
     */
    const listenerLineStatus = (userCode, type) => {
        // 当前若有报错提示，则不展示上下线信息，录音正常的情况下才可展示上/下线提示（非录音面试官）
        if (userCode !== recHOSTuserCodeRef.current) {
            if (
                warningRef.current === WARNING_TYPES.NONE ||
                warningRef.current === WARNING_TYPES.ONLINE ||
                warningRef.current === WARNING_TYPES.OFFLINE
            ) {
                wsuserCode.current = userCode;
                if (onlineOfflineTimmerRef.current) {
                    // 若已有上下线信息，则先清除定时器
                    clearTimeout(onlineOfflineTimmerRef.current);
                }
                events.emit(EVENTBUS_TYPES.SET_EXTEND, true);
                proxySetWarningType(type);
                console.log('vv-type: ', type);
                // 设置10秒后上下线信息消失且自动收起面试官看板
                onlineOfflineTimmerRef.current = setTimeout(() => {
                    proxySetWarningType(WARNING_TYPES.NONE);
                    events.emit(EVENTBUS_TYPES.SET_EXTEND, false);
                }, 10000);
            }
        }
    };
    const handleDisconnect = useCallback(() => {
        // 处理非主录音者的网络断开，主录音者的在 useRealTimeUpload.js
        setRemoteRECState(2);
        remoteRECStateRef.current = 2;
    }, []);

    useEffect(() => {
        // 监听本地断网
        window.addEventListener('offline', handleDisconnect);
        // 监听 websocket断开
        events.addListener(EVENTBUS_TYPES.SOCKET_DISCONNECT, handleDisconnect);
        // 监听警示条的变化
        events.addListener(EVENTBUS_TYPES.SET_WARNING, setWarningHandler);
        // 记录已打开的面试记录页面
        dispatch({
            type: 'interviewREC/addActivedInterviewPage',
            arrangeId: Number(arrangeId)
        });
        return () => {
            window.removeEventListener('offline', handleDisconnect);
            events.removeListener(EVENTBUS_TYPES.SOCKET_DISCONNECT, handleDisconnect);
            events.removeListener(EVENTBUS_TYPES.SET_WARNING, setWarningHandler);
            console.log('离开页面时，清空计时器');
            clearInterval(setRemoteRECDurationTimmer); // 离开页面时，清空计时器
            clearInterval(checkStartTimeTimmer);
            clearTimeout(hoverLoadingTimmer);
            dispatch({
                type: 'interviewREC/removeInterviewPage',
                arrangeId: Number(arrangeId)
            });
        };
    }, []);

    const [evaluationInfo, setEvaluationInfo] = useState({});
    const [recData, setRecData] = useState({
        // 后端保存的，录音相关数据
        recordContinueKey: '',
        recordUrl: '',
        recordUrlState: -1,
        recordTimeInfo: ''
    });
    const scrollWrapRef = useRef();
    // const recordButtonRef = useRef();

    // 获取其它用户的自定义问题
    const { run: getQuestion, cancel: cancelGetQuestion } = useRequest(() => getOtherQuestions(arrangeId), {
        ...defaultFormatResult,
        manual: true,
        // pollingInterval: 5000,
        onSuccess(data) {
            const isPageActived = isCurrentPageActived(currentHref.current);
            if (!(data instanceof Array)) {
                return;
            }
            let render = false;
            let nextFormList = (getFieldValue('interviewQuestions') || []).slice();
            console.log('获取其它用户的自定义问题：', nextFormList);
            const selfFormList = nextFormList.filter(item => item.isEqual); // 只保留自己的
            data.forEach((item, index) => {
                const { id: newId, createUserName, question: newQuestion, answer: newAnswer } = item || {};
                const oldIndex = nextFormList.findIndex(old => old.id === newId);
                // 新增
                const selfFormLen = selfFormList.length;
                if (oldIndex === -1) {
                    render = true;
                    const len = selfFormLen + index + 1;
                    if (isPageActived) {
                        message.info(`${createUserName} 新增了面试问题 ${len}`);
                    }
                } else {
                    // 更新
                    const old = nextFormList[oldIndex] || {};
                    const { question: oldQuestion, answer: oldAnswer } = old;
                    const oldAnswerContent = oldAnswer?.answerContent;
                    const newAnswerContent = newAnswer?.answerContent;
                    if (newQuestion !== oldQuestion) {
                        render = true;
                        if (isPageActived) {
                            message.info(`${createUserName} 更新了面试问题 ${oldIndex + 1}`);
                        }
                    }
                    if (oldAnswerContent !== newAnswerContent) {
                        render = true;
                        if (isPageActived) {
                            message.info(`${createUserName} 更新了面试问题 ${oldIndex + 1} 的候选人答复`);
                        }
                    }
                    // if (selfFormLen + index !== oldIndex) {
                    //     render = true;
                    //     message.info(`${createUserName} 更新了面试问题 ${oldIndex + 1} 的顺序`);
                    // }
                    // eslint-disable-next-line no-param-reassign
                    item.answer.answerTimes = item?.answer?.recordTimeInfo
                        ? JSON.parse(item.answer.recordTimeInfo)
                        : []; // 创建问题录音片段
                    data[index] = {
                        ...old,
                        ...item
                    };
                }
            });
            const removed = [];
            // 移除删除的
            nextFormList = nextFormList.filter((old, index) => {
                const parse = old.isEqual || data.findIndex(current => current.id === old.id) !== -1;
                if (!parse) {
                    render = true;
                    removed.push({
                        number: index + 1,
                        createUserName: old.createUserName
                    });
                }
                return parse;
            });
            removed.forEach(item => {
                if (isPageActived) {
                    message.info(`${item.createUserName} 删除了面试问题 ${item.number}`);
                }
            });
            console.log('获取其它用户的面试问题：', [...selfFormList, ...data]);
            if (render) {
                setFieldsValue({
                    interviewQuestions: [...selfFormList, ...data]
                });
            }
        }
    });

    /**
     * 设置问题的录音片段
     * 返回 true 需要调用接口更新整个问题，返回false则无需
     */
    const setQuestionREC = (id, answerTimes) => {
        const nextFormList = (getFieldValue('interviewQuestions') || []).slice();
        for (let index = 0; index < nextFormList.length; index += 1) {
            const element = nextFormList[index];
            if (element.id === id) {
                if (JSON.stringify(element.answer.answerTimes) === JSON.stringify(answerTimes)) {
                    console.log('更新子问题答复');
                    return true; // 录音相同，代表更新其它字段
                }
                element.answer.answerTimes = answerTimes;
                break;
            }
        }
        setFieldsValue({
            interviewQuestions: nextFormList
        });
        console.log('更新子问题录音列表');
        return false; // 能走到这里，代表更新的是录音，则无需调用接口
    };

    /**
     * 获取上传后的录音信息，如URL，
     * ！！！追加上传后使用！！！
     */
    const getRecInfo = useCallback(async () => {
        const interviewData = await getInterviewProcedure(arrangeId);
        const { interviewArrange = {} } = interviewData.data;
        const { recordTimeInfo, recordContinueKey, recordUrl, recordUrlState } = interviewArrange;
        const res = {
            recordContinueKey,
            recordUrl,
            recordUrlState,
            recordTimeInfo
        };
        setRecData(res);
        return res;
    }, [arrangeId]);

    const allow = useRef(true); // 仅需要在启动后获取一次url、时间等录音相关信息
    /**
     * 上传主录音信息，追加上传专用
     * realtionArr 用于构建资源关系，仅在首次上传时添加
     */
    const uploadRecInfo = async (recordContinueKey, recordUrlState, endTime, startTime, realtionArr = null) => {
        const reqObj = {
            arrangeId,
            recordContinueKey,
            recordUrlState,
            recordTimeInfo: {
                endTime,
                startTime,
                sort: 1
            }
        };
        // 首次上传需要构建资源关系
        if (realtionArr) {
            reqObj.resourceRelation = realtionArr;
        }
        const res = await saveInterviewRecord(reqObj);
        console.log('上传主录音信息，追加上传专用');
        console.log(res);
        if (allow.current && res.code === 10000 && realtionArr) {
            getRecInfo();
            allow.current = false;
        }
    };

    const [recorderState, duration, durationMSRef, realTimeRECRef, uploadState] = useRealTimeUpload(
        recData.recordUrl,
        `interview-${arrangeId}.mp3`,
        recData.recordContinueKey,
        pageLoading,
        uploadRecInfo,
        recData.recordTimeInfo
    );

    /**
     * 在录制中的状态下，停止录音
     */
    const stopREC = () => {
        if (realTimeRECRef.current && realTimeRECRef.current.myRecorderState === 1) {
            // 本地录音状态校验，若在录音，直接停止，停止后会自动上传剩余部分 + 上报
            realTimeRECRef.current.stopRec();
        }
    };

    useEffect(
        () => () => {
            console.log('页面卸载，停止录音');
            stopREC();
        },
        []
    );

    /**
     *  检查是否已超过面试开始时间，需要延迟 10s 执行，给网络通信时间
     *  如果是主录音是本人，就不出现这个提示
     */
    const checkIfPassStartTime = () => {
        checkStartTimeTimmer = setInterval(() => {
            if (
                interviewStartTimeRef.current < Date.now() && // 已超过面试开始时间
                remoteRECStateRef.current === -1 && // 远程无录音
                recorderState === -1 // 本地无录音
            ) {
                if (warningRef.current !== WARNING_TYPES.NONE) {
                    // 已有警告的情况下，啥都不做
                } else if (recHOSTuserCode !== user) {
                    events.emit(EVENTBUS_TYPES.SET_WARNING, WARNING_TYPES.NOTICE);
                } else {
                    events.emit(EVENTBUS_TYPES.SET_WARNING, WARNING_TYPES.CLOSE_REENTER);
                }
                clearInterval(checkStartTimeTimmer);
                checkStartTimeTimmer = null;
            }
        }, 5000);
    };

    useBeforeInterview({ arrangeId }); // 面试前校验
    const [onlineList, setOnlineList] = useState([user]); // 在线面试官 userCode 数组
    const onlineListRef = useRef([]); // 暂存onlineList数据
    const [onBeforeStart] = useMultiInterviewersV2(onlineListRef, interviewersArr); // 检查未上线面试官
    const localWsRef = useRef(null); // 为了能调用到websocket的实例

    /**
     * 处理用户正常下线，若对方是主录音且正则录音，则需要切断录音。
     * isAbnormal 异常下线
     */
    const handleOffline = (userCode, isAbnormal) => {
        console.log('vv-isAbnormal: ', isAbnormal, userCode, user);
        if (onlineListRef.current.includes(userCode)) {
            listenerLineStatus(userCode, WARNING_TYPES.OFFLINE);
            console.log('剔除：', userCode);
            const index = onlineListRef.current.indexOf(userCode);
            onlineListRef.current.splice(index, 1);
            setOnlineList([...onlineListRef.current]);
            console.log('handleOffline:', userCode, recHOSTuserCodeRef.current, remoteRECState);
            if (userCode === recHOSTuserCodeRef.current && remoteRECStateRef.current === 1) {
                // 主录音下线且主录音正在录音
                clearInterval(setRemoteRECDurationTimmer);
                setRemoteRECState(2);
                remoteRECStateRef.current = 2; // 远程录音设置为暂停状态
                setRemoteRECDuration(remoteRECDurationRef.current);
                if (isAbnormal) {
                    // 异常下线
                    message.warning('录音已暂停，请立即开启录音');
                    proxySetWarningType(WARNING_TYPES.PAUSED);
                    events.emit(EVENTBUS_TYPES.PLAY_ALARM); // 警告音
                    events.emit(EVENTBUS_TYPES.SET_EXTEND, true);
                    events.emit(EVENTBUS_TYPES.SHAKE);
                } else proxySetWarningType(WARNING_TYPES.PAUSED); // 正常下线
                events.emit(EVENTBUS_TYPES.STOP_SUB_REC); // 主录音者停止录音，也要切断子录音
            }
        }
    };

    /**
     * 处理用户异常掉线的情况 or 系统推送的上线信息
     */
    const serverPushUserstateHandler = wsRes => {
        let msgBody = wsRes?.msg?.body;
        if (msgBody) {
            msgBody = JSON.parse(msgBody);
            console.log('%c已有用户改变上下线状态！', 'color: #ff0000', msgBody);
            if (msgBody.data.state === '0' && onlineListRef.current.includes(msgBody.data.userCode)) {
                console.log('异常下线：', msgBody.data);
                handleOffline(msgBody.data.userCode, true);
            } else if (msgBody.data.state === '1' && !onlineListRef.current.includes(msgBody.data.userCode)) {
                // 收到用户上线信息
                onlineListRef.current.push(msgBody.data.userCode);
                listenerLineStatus(msgBody.data.userCode, WARNING_TYPES.ONLINE);
                setOnlineList([...onlineListRef.current]);
            }
        }
    };

    /**
     * 批量设置远程录音信息
     */
    const remoteRECStateHandler = (state, durationMS1, fold = true) => {
        console.log('批量设置远程录音信息', state, durationMS1);
        setRemoteRECState(state);
        remoteRECStateRef.current = state;
        setRemoteRECDuration(durationMS1);
        remoteRECDurationRef.current = durationMS1;
        if (state === 1) {
            if (fold) {
                proxySetWarningType(WARNING_TYPES.NONE);
                events.emit(EVENTBUS_TYPES.SET_EXTEND, false);
            }
            clearInterval(setRemoteRECDurationTimmer);
            setRemoteRECDurationTimmer = setInterval(() => {
                remoteRECDurationRef.current += 1000;
                setRemoteRECDuration(remoteRECDurationRef.current);
            }, 1000);
        } else if (state === 2) {
            if (recHOSTuserCodeRef.current !== user) {
                // 本人非主录音
                message.warning('录音已暂停，请立即开启录音');
                proxySetWarningType(WARNING_TYPES.PAUSED);
            }
            clearInterval(setRemoteRECDurationTimmer);
        } else {
            clearInterval(setRemoteRECDurationTimmer);
        }
        if (state !== 1) {
            // 如果是暂停、停止状态，则自动停止录音
            events.emit(EVENTBUS_TYPES.STOP_SUB_REC); // 停止子录音
        }
        // 如果自己不是主录音，就从服务端获取kayName、url、录音总长度...等数据----这个会在录制、暂停、停止状态下执行
        if (user !== recHOSTuserCodeRef.current) {
            getRecInfo();
        }
    };

    /**
     * 收到远程发来的warning，显示告警条
     */
    const showWarningHandler = (warningType1, remoteUserCode, myUserCode) => {
        if (remoteUserCode !== myUserCode) {
            proxySetWarningType(warningType1);
        }
    };

    /**
     * 设置主录音者userCode
     */
    const setRecHOSTuserCodeFun = code => {
        setRecHOSTuserCode(code);
        recHOSTuserCodeRef.current = code;
        localStorage.setItem(
            'recHOSTuserCode',
            JSON.stringify({
                user: code,
                arrangeId
            })
        );
    };

    /**
     * 处理用户上线的情况
     */
    const handleOnline = wsRes => {
        if (interviewersArrRef.current.length !== 0) {
            // 有面试官列表了再做过滤，没有就不做了
            if (!interviewersArrRef.current.includes(wsRes.data.userCode)) {
                return; // 非本次面试的面试官，就不往下走了
            }
        }
        if (!onlineListRef.current.includes(wsRes.data.userCode)) {
            onlineListRef.current.push(wsRes.data.userCode);
            setOnlineList([...onlineListRef.current]);
            console.log('加入数组：', wsRes.data.userCode);
        }
        if (wsRes.data.lastHost === user) {
            // 处理主录音掉线后刷新的情况，此时需要其他面试官传递来 lastHost 最后一个主录音者的数据
            setRecHOSTuserCodeFun(wsRes.data.lastHost);
        }
        // 在有面试官新上线的情况下，发送响应报文，需排除掉自己
        if (wsRes.data.isPassive === false && wsRes.data.userCode !== user) {
            passiveTriggerOnlineEvent(
                localWsRef,
                user,
                recHOSTuserCodeRef.current === user,
                realTimeRECRef.current?.myRecorderState,
                realTimeRECRef.current?.onLinePartDuration,
                remoteRECStateRef.current,
                recHOSTuserCodeRef.current
            );
        }
        // 在其它面试官为主录音，且开启录音情况下，设置主录音
        if (wsRes.data.timeStamp !== null && wsRes.data.timeStamp !== undefined && wsRes.data.isPassive) {
            remoteRECStateHandler(1, wsRes.data.timeStamp, false);
            setRecHOSTuserCodeFun(wsRes.data.userCode);
        }
        // 其它面试官是主录音，且未开启主录音的情况下，清空本地主录音设置，避免保留有localstorage中不正确的主录音记录
        if ((wsRes.data.timeStamp === null || wsRes.data.timeStamp === undefined) && wsRes.data.isHost) {
            setRecHOSTuserCodeFun('');
            if (wsRes.data.hostPaused) {
                proxySetWarningType(WARNING_TYPES.PAUSED);
            }
        }
    };

    /**
     * 处理websocket传入的事件
     */
    const wsEventHandler = res => {
        const wsRes = JSON.parse(res?.msg?.body);
        switch (wsRes.type) {
            case WEBSOCKET_TYPES.ADD_QUESTION:
                console.log('收到问题更新事件');
                getQuestion();
                break;
            case WEBSOCKET_TYPES.EDIT_ANSWER:
                console.log('收到问题更新事件 --- 添加答复 or 添加录音片段', wsRes);
                if (wsRes.answerTimes) {
                    if (setQuestionREC(wsRes.questionId, wsRes.answerTimes)) {
                        getQuestion();
                    }
                } else {
                    getQuestion();
                }
                break;
            case WEBSOCKET_TYPES.ONLINE:
                console.log('用户上线：', wsRes);
                handleOnline(wsRes);
                break;
            case WEBSOCKET_TYPES.OFFLINE:
                console.log('用户下线：', wsRes);
                handleOffline(wsRes.userCode);
                break;
            case WEBSOCKET_TYPES.FIGHT_FOR_HOST:
                console.log('有人开始争夺主录音权限：', wsRes);
                handleFightEvent(localWsRef, user, wsRes);
                break;
            case WEBSOCKET_TYPES.RESPONSE_FOR_FIGHT:
                console.log('开始争夺主录音权限：', wsRes);
                handleResponseForFight(localWsRef, user, onlineListRef, wsRes, recHOSTuserCodeRef);
                break;
            case WEBSOCKET_TYPES.SET_HOST:
                console.log('设置主录音者userCode：', wsRes);
                setRecHOSTuserCodeFun(wsRes.userCode);
                break;
            case WEBSOCKET_TYPES.SET_REC_STATE:
                console.log('主录音状态变化：', wsRes);
                remoteRECStateHandler(wsRes.data.state, wsRes.data.durationMS);
                break;
            case WEBSOCKET_TYPES.SHOW_MESSAGE:
                console.log('show message：', wsRes);
                showMessageHandler(wsRes.msgType, wsRes.msg, wsRes.userCode, user);
                break;
            case WEBSOCKET_TYPES.SEND_WARNING:
                console.log('show WARNING:', wsRes);
                showWarningHandler(wsRes.warningType, wsRes.userCode, user);
                break;
            default:
                console.log('自定义事件已收到！未处理：', wsRes);
                break;
        }
    };
    const [wsRef] = useSocket(
        user,
        `interview${arrangeId}`,
        `jms.topic.arrangeId${arrangeId}`,
        wsEventHandler,
        serverPushUserstateHandler
    );
    localWsRef.current = wsRef;

    const sharedEventHandler = res => {
        const msgBody = JSON.parse(res?.msg?.body);
        console.log('面试准备页收到报文：', msgBody);
        if (msgBody.type === WEBSOCKET_TYPES.SHARED_UPDATE_QUESTION) {
            if (msgBody.data.userCode !== user) {
                // 过滤自己在面试记录页面发送的报文
                getQuestion();
            }
        }
    };
    const [sendUpdateQuestionMsg] = useSharedSocket(
        user,
        `sharedChannel${arrangeId}`,
        `jms.topic.shared${arrangeId}`,
        sharedEventHandler
    );

    /**
     * 在websocket中广播问题更新报文
     */
    const broadcastUpdateMsg = () => {
        sendUpdateQuestionMsg(true);
    };

    /**
     * 监听【本地】录音状态变化,当变化时，往websocket发送
     */
    const handleRECStateChange = state => {
        if (state !== 1) {
            events.emit(EVENTBUS_TYPES.STOP_SUB_REC); // 停止子录音
        }
        wsRef.current.send({
            type: WEBSOCKET_TYPES.SET_REC_STATE,
            data: {
                state,
                durationMS: realTimeRECRef.current.onLinePartDuration
            }
        });
        // 如果停止录音，需要上报服务器。
        if (state === 0) {
            saveInterviewRecord({
                arrangeId,
                recordUrlState: 1 // 0 未停止， 1 停止
            });
        }
    };

    const sendMsgToSocket = (msgType, msg, userCode) => {
        wsRef.current.send({
            type: WEBSOCKET_TYPES.SHOW_MESSAGE,
            msgType,
            msg,
            userCode
        });
    };
    const sendWarningToSocket = (warningType1, userCode) => {
        wsRef.current.send({
            type: WEBSOCKET_TYPES.SEND_WARNING,
            userCode,
            warningType: warningType1
        });
    };
    // 监听 本地录音状态变化、 警告状态变化
    useEffect(() => {
        events.addListener(WEBSOCKET_TYPES.SET_REC_STATE, payload => {
            handleRECStateChange(payload);
        });
        events.addListener(WEBSOCKET_TYPES.SHOW_MESSAGE, payload => {
            sendMsgToSocket(payload?.msgType, payload?.msg, payload?.userCode);
        });
        events.addListener(WEBSOCKET_TYPES.SEND_WARNING, payload => {
            sendWarningToSocket(payload, user);
        });
        return () => {
            events.removeListener(WEBSOCKET_TYPES.SET_REC_STATE);
            events.removeListener(WEBSOCKET_TYPES.SHOW_MESSAGE);
            events.removeListener(WEBSOCKET_TYPES.SEND_WARNING);
        };
    }, []);

    /**
     * 开始主录音权限争夺
     */
    const fightForHost = () => {
        startFightForHost(localWsRef, user, onlineListRef);
    };

    /**
     * 混合线上与本地的录音状态
     */
    const mixedRecordState = useMemo(() => {
        if (recorderState === 1 || remoteRECState === 1) {
            return 1;
        }
        if (recorderState === 0 && remoteRECState === 0) {
            return 0;
        }
        if (recorderState === -1 && remoteRECState === -1) {
            return -1;
        }
        return 2;
    }, [recorderState, remoteRECState]);

    const mixedRecordStateRef = useRef(-1);
    useEffect(() => {
        mixedRecordStateRef.current = mixedRecordState;
    }, [mixedRecordState]);

    /**
     * 混合线上与本地的录音状态 + 上传状态
     */
    const mixedRecordAndUploadState = useMemo(() => {
        if (uploadState || recorderState === 1 || remoteRECState === 1) {
            return 1;
        }
        if (recorderState === 0 && remoteRECState === 0) {
            return 0;
        }
        if (recorderState === -1 && remoteRECState === -1) {
            return -1;
        }
        return 2;
    }, [recorderState, remoteRECState, uploadState]);

    /**
     * 获取主录音状态，问题录音标记使用，兼容老代码
     */
    const getRecordState = useCallback(() => mixedRecordState, [mixedRecordState]);

    /**
     * 初始化面试数据，只调用一次
     */
    const getInfo = async () => {
        try {
            setPageLoading(true);
            const [evaluationData, interviewData] = await Promise.all([
                getTalentMessage(candidateId),
                getInterviewProcedure(arrangeId)
            ]);
            // 取完数据后，获取一次自定义问题。
            getQuestion();
            if (evaluationData.code === 10000) {
                setEvaluationInfo(evaluationData.data);
            }
            if (interviewData.code === 10000) {
                console.log('面试准备数据', interviewData);
                let {
                    selfInterviewQuestions = [],
                    othersInterviewQuestions = [],
                    evaluateFormInsts = []
                } = interviewData.data;
                const { interviewArrange = {} } = interviewData.data;
                const {
                    interviewEmployeeVOList,
                    recordTimeInfo,
                    recordContinueKey,
                    recordUrl,
                    recordUrlState,
                    interviewStartTime // 面试开始时间
                } = interviewArrange;
                interviewStartTimeRef.current = moment(interviewStartTime, 'YYYY-MM-DD hh:mm:ss');
                setRecData({
                    recordContinueKey,
                    recordUrl,
                    recordUrlState,
                    recordTimeInfo
                });
                if (!recordUrl) {
                    // 没上传过录音的情况下，才检查是否已经超过面试开始时间
                    checkIfPassStartTime();
                } else {
                    // 已上传过录音的情况下，一律弹出暂停对应提示
                    setTimeout(() => {
                        if (mixedRecordStateRef.current > 1 || mixedRecordStateRef.current === -1) {
                            proxySetWarningType(WARNING_TYPES.PAUSED);
                        }
                    }, 4000);
                }
                const { relateFormItemMap = {} } = interviewData.data;
                checkIsPermitted(interviewEmployeeVOList, user);
                setInterviewersArr(interviewEmployeeVOList);
                interviewEmployeeVOList.forEach(item => {
                    interviewersArrRef.current.push(item.employeeCode);
                });
                hoverLoadingTimmer = setTimeout(() => {
                    events.emit(EVENTBUS_TYPES.SET_LOADING, false);
                }, 3000);
                selfInterviewQuestions = selfInterviewQuestions.map(item => {
                    const comment = formatComment(item.comments);
                    return {
                        ...item,
                        comment,
                        answer: { ...item.answer, answerTimes: JSON.parse(item?.answer?.recordTimeInfo || '[]') },
                        isAnswerEdit: !item?.answer?.answerContent,
                        isCommentEdit: !comment?.commentContent,
                        isEqual: true
                    };
                });
                othersInterviewQuestions = othersInterviewQuestions.map(item => {
                    const comment = formatComment(item.comments);
                    return {
                        ...item,
                        comment,
                        answer: { ...item.answer, answerTimes: JSON.parse(item?.answer?.recordTimeInfo || '[]') },
                        isCommentEdit: false
                    };
                });
                evaluateFormInsts = evaluateFormInsts.map(item => ({
                    ...item,
                    formItems: (item.formItems || []).map(formItem => ({
                        ...formItem,
                        itemEvaluateReason: '',
                        itemEvaluateScore: '',
                        history: relateFormItemMap[`${item.formId}_${formItem.itemId}`]
                    }))
                }));
                setRecruitEvaluateList(evaluateFormInsts);
                // setInterviewProcedure(interviewData.data);
                setFieldsValue({
                    interviewQuestions: [...selfInterviewQuestions, ...othersInterviewQuestions]
                });
            }
            setPageLoading(false);
        } catch (e) {
            console.log(e);
            setPageLoading(false);
        }
    };

    useEffect(() => {
        message.config({
            maxCount: 100
        });
        getInfo();
        // 临时解决：录音启动后退出页面无法继续录音的操作
        resetInterviewRecordState(arrangeId);
        return () => {
            cancelGetQuestion();
            // 在request.js中有对这个做限制，把它还原
            message.config({
                maxCount: 1
            });
        };
    }, []);

    /**
     * 提交面试结果
     */
    const onInterviewSubmit = debounce(async () => {
        try {
            validateFieldsAndScroll(async (err, values) => {
                // 问题录音在 form 中校验
                console.log(values);
                if (!err) {
                    stopREC();
                    const { evaluateResult, interviewQuestions = [], recruitEvaluateForm } = values;
                    const extraParam = recruitEvaluateForm ? { recruitEvaluateForm } : {};
                    setPageLoading(true);
                    const params = {
                        arrangeId,
                        candidateId,
                        evaluateResult,
                        interviewQuestions,
                        ...extraParam
                        // ...(recordButtonRef.current ? await recordButtonRef.current.getRecordInfo() : {})
                    };
                    const { code, msg } = await onSaveInterviewprocedure(params); // 上传服务器
                    if (code === 10000) {
                        message.success('提交成功！');
                        pageTabUtil.goBack();
                    } else {
                        message.error(msg);
                    }
                    setPageLoading(false);
                }
            });
        } catch (e) {
            console.log(e);
            setPageLoading(false);
        }
    }, 400);

    /**
     * 渲染录音组件或播放器
     */
    const renderRecOrPlayer = () => {
        if (recData.recordUrlState === -1) {
            // 未初始化时不显示
            return null;
        }
        if ((recorderState === 0 || remoteRECState === 0 || recData.recordUrlState === 1) && !uploadState) {
            return (
                <TitleControl title="面试录音">
                    <WebAudio src={recData.recordUrl} controls="controls" />
                </TitleControl>
            );
        }
        return (
            <HoverRECButton
                mixedRecordState={mixedRecordState}
                recData={recData}
                onBeforeStart={onBeforeStart}
                getRecInfo={getRecInfo}
                userCode={user}
                wsuserCode={wsuserCode.current}
                realTimeRECRef={realTimeRECRef}
                recorderState={recorderState}
                duration={duration}
                interviewersArr={interviewersArr}
                onlineList={onlineList}
                warningType={warningType}
                fightForHost={fightForHost}
                recHOSTuserCode={recHOSTuserCode}
                remoteRECState={remoteRECState}
                remoteRECStateRef={remoteRECStateRef}
                remoteRECDuration={remoteRECDuration}
            ></HoverRECButton>
        );
    };

    return (
        <div ref={scrollWrapRef}>
            <PageContainer>
                <Spin spinning={pageLoading}>
                    <TalentInfoHead talent={evaluationInfo} />
                    <AlarmAudioPlayer
                        recData={recData}
                        warningType={warningType}
                        userCode={user}
                        recHOSTuserCode={recHOSTuserCode}
                    />
                    {/* 停止录音后回显,recorderState本地录音状态，remoteRECState远 ws传递来的远程状态，recData.recordUrlState 后端保存的状态   */}
                    {renderRecOrPlayer()}
                    <TitleControl title="面试问题">
                        <div className={styles.questionTip}>完成编辑后，答复将自动保存并展示给其他面试官</div>
                        {getFieldDecorator('interviewQuestions', {
                            initialValue: []
                        })(
                            <Question
                                broadcastUpdateMsg={broadcastUpdateMsg}
                                form={form}
                                uploadState={uploadState}
                                wsRef={wsRef}
                                getRecordState={getRecordState}
                                arrangeId={arrangeId}
                                disableButton={recorderState === 0 || recData.recordUrlState === 1}
                                scrollWrapRef={scrollWrapRef}
                                durationMSRef={
                                    durationMSRef.current > remoteRECDurationRef.current
                                        ? durationMSRef
                                        : remoteRECDurationRef
                                }
                                recData={recData}
                                mixedRecordAndUploadState={mixedRecordAndUploadState}
                            />
                        )}
                    </TitleControl>
                    {recruitEvaluateList && recruitEvaluateList.length ? (
                        <TitleControl title="能力评估">
                            {recruitEvaluateList.map((item, index) =>
                                getFieldDecorator(`recruitEvaluateForm[${index}]`, { initialValue: item || {} })(
                                    <AssessFrom
                                        key={item.id}
                                        form={form}
                                        tableIdName="itemId"
                                        isExpandedRowRender
                                        settings={{
                                            checkIs: 0,
                                            starIs: 1,
                                            scoreIs: 1,
                                            textIs: 1,
                                            passScoreIs: 1
                                        }}
                                    />
                                )
                            )}
                        </TitleControl>
                    ) : null}
                    <TitleControl title="综合评价" bottomBorder={false} showButton={false}>
                        <Evaluation
                            form={form}
                            onSubmit={onInterviewSubmit}
                            resumeId={evaluationInfo?.recruitTalentMatcherId}
                            style={{ width: 460 }}
                            keyPrefix="evaluateResult."
                        />
                    </TitleControl>
                </Spin>
            </PageContainer>
        </div>
    );
};

export default connect(({ user }) => ({ user: user?.currentUser?.employeeCode }))(Form.create()(Record));
